/**
 * @File name: yhstm32f4v0.c
 * @Synopsis:
 * @Author: xing.dai@aliyun.com
 * @Version: 0.0.1
 * @Date: 2018-07-30 18:52
 */

#include "board.h"
#include "os.h"
#include "stm32f4xx_conf.h"
#include <stdio.h>
#include "includes.h"
#include "init.h"
//#include "uart.h"

#define CONSOLE_DEVICE_NAME     "uart1"


#define  BSP_REG_DEM_CR                           (*(CPU_REG32 *)0xE000EDFC)
#define  BSP_REG_DWT_CR                           (*(CPU_REG32 *)0xE0001000)
#define  BSP_REG_DWT_CYCCNT                       (*(CPU_REG32 *)0xE0001004)
#define  BSP_REG_DBGMCU_CR                        (*(CPU_REG32 *)0xE0042004)


#define  BSP_BIT_DEM_CR_TRCENA                    DEF_BIT_24
#define  BSP_BIT_DWT_CR_CYCCNTENA                 DEF_BIT_00


#define LED_RGB_CLK         RCC_AHB1Periph_GPIOH
#define LED_RGB_PORT        GPIOH
#define LED_RED_PIN         GPIO_Pin_10
#define LED_GREEN_PIN       GPIO_Pin_11
#define LED_BLUE_PIN        GPIO_Pin_12

#define LED_CLK         RCC_AHB1Periph_GPIOD
#define LED_PORT        GPIOD
#define LED_PIN         GPIO_Pin_11


CPU_INT32U  BSP_CPU_ClkFreq (void);

/**
 * @Synopsis  Disable all interrupts, caller is system begin.
 */
void bsp_int_disable_all(void)
{

}

void rcc_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Output HSE clock on MCO1 pin(PA8) ****************************************/

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    /* Configure MCO1 pin(PA8) in alternate function */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* HSE clock selected to output on MCO1 pin(PA8)*/
    RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1);


    /* Output SYSCLK/4 clock on MCO2 pin(PC9) ***********************************/

    /* Configure MCO2 pin(PC9) in alternate function */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* SYSCLK/4 clock selected to output on MCO2 pin(PC9)*/
    RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO2Div_4);



    /* Enable peripheral */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOH, ENABLE);
}

/**
 * @Synopsis  systicm init.
 *
 * @Returns  0: success.
 */
int  bsp_tick_init (void)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;


    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */

#if (OS_VERSION >= 30000u)
    cnts = (cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz);      /* Determine nbr SysTick increments                     */
#else
    cnts = (cpu_clk_freq / (CPU_INT32U)OS_TICKS_PER_SEC);       /* Determine nbr SysTick increments.                    */
#endif

    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */
    return 0;
}

/**
 * @Synopsis  init led pin config.
 *
 * @Returns  0: success.
 */
int led_gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = LED_RED_PIN | LED_GREEN_PIN | LED_BLUE_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(LED_RGB_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = LED_PIN;
    GPIO_Init(LED_PORT, &GPIO_InitStructure);

    return 0;
}

/**
 * @Synopsis  Set RGB LED light.
 *
 * @Param index: RED, GREEN...
 */
void rgb_led(int index)
{
    switch (index) {
        case RED: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_SET);
            break;
        }

        case GREEN: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_SET);
            break;
        }
        case BLUE: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_RESET);
            break;
        }
        case YELLOW: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_SET);
            break;
        }
        case PURPLE: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_RESET);
            break;
        }
        case CYAN: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_RESET);
            break;
        }
        case WHITE: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_RESET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_RESET);
            break;
        }
        case RGB_OFF: {
            GPIO_WriteBit(LED_RGB_PORT, LED_RED_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_GREEN_PIN, Bit_SET);
            GPIO_WriteBit(LED_RGB_PORT, LED_BLUE_PIN, Bit_SET);
            break;
        }

        default:
            break;
    }
}


static int uart_low_config(struct _config_init *pra)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Peripheral Clock Enable -------------------------------------------------*/
    /* Enable GPIO clock */
    RCC_AHB1PeriphClockCmd(USART1_TX_GPIO_CLK | USART1_RX_GPIO_CLK, ENABLE);

    /* Enable USART clock */
    USART1_CLK_INIT(USART1_CLK, ENABLE);

    /* USART1 GPIO configuration -----------------------------------------------*/
    /* Connect USART pins to AF7 */
    GPIO_PinAFConfig(USART1_TX_GPIO_PORT, USART1_TX_SOURCE, USART1_TX_AF);
    GPIO_PinAFConfig(USART1_RX_GPIO_PORT, USART1_RX_SOURCE, USART1_RX_AF);

    /* Configure USART Tx and Rx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

    GPIO_InitStructure.GPIO_Pin = USART1_TX_PIN;
    GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = USART1_RX_PIN;
    GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStructure);

    /* USART1 configuration ----------------------------------------------------*/
    /* Enable the USART OverSampling by 8 */
    USART_OverSampling8Cmd(USART1, ENABLE);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    /* When using Parity the word length must be configured to 9 bits */
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    /* Enable USART */
    USART_Cmd(USART1, ENABLE);
    return 0;
}

CONFIG_HW_INIT(uart_init, uart_low_config, NULL, HW_INIT_LEVEL_1);

/**
 * @Synopsis  Read cpu regitsters to determine the cpu clock frequency of the chip.
 *
 * @Returns   The cpu clock frequency, in Hz.
 */
CPU_INT32U  BSP_CPU_ClkFreq (void)
{
    RCC_ClocksTypeDef  rcc_clocks;


    RCC_GetClocksFreq(&rcc_clocks);

    return ((CPU_INT32U)rcc_clocks.HCLK_Frequency);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                          CPU_TS_TmrInit()
*
* Description : Initialize & start CPU timestamp timer.
*
* Argument(s) : none.
*
* Return(s)   : none.
*
* Caller(s)   : CPU_TS_Init().
*
*               This function is an INTERNAL CPU module function & MUST be implemented by application/
*               BSP function(s) [see Note #1] but MUST NOT be called by application function(s).
*
* Note(s)     : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer
*                   if either of the following CPU features is enabled :
*
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*
*               (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
*                       data type.
*
*                       (1) If timer has more bits, truncate timer values' higher-order bits greater
*                           than the configured 'CPU_TS_TMR' timestamp timer data type word size.
*
*                       (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
*                           timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
*                           configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
*
*                           In other words, if timer size is not a binary-multiple of 8-bit octets
*                           (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
*                           octet word size SHOULD be configured (e.g. to 16-bits).  However, the
*                           minimum supported word size for CPU timestamp timers is 8-bits.
*
*                       See also 'cpu_cfg.h   CPU TIMESTAMP CONFIGURATION  Note #2'
*                              & 'cpu_core.h  CPU TIMESTAMP DATA TYPES     Note #1'.
*
*                   (b) Timer SHOULD be an 'up'  counter whose values increase with each time count.
*
*                   (c) When applicable, timer period SHOULD be less than the typical measured time
*                       but MUST be less than the maximum measured time; otherwise, timer resolution
*                       inadequate to measure desired times.
*
*                   See also 'CPU_TS_TmrRd()  Note #2'.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void  CPU_TS_TmrInit (void)
{
    CPU_INT32U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();

    BSP_REG_DEM_CR     |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA;    /* Enable Cortex-M4's DWT CYCCNT reg.                   */
    BSP_REG_DWT_CYCCNT  = (CPU_INT32U)0u;
    BSP_REG_DWT_CR     |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;

    CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
}
#endif


/*$PAGE*/
/*
*********************************************************************************************************
*                                           CPU_TS_TmrRd()
*
* Description : Get current CPU timestamp timer count value.
*
* Argument(s) : none.
*
* Return(s)   : Timestamp timer count (see Notes #2a & #2b).
*
* Caller(s)   : CPU_TS_Init(),
*               CPU_TS_Get32(),
*               CPU_TS_Get64(),
*               CPU_IntDisMeasStart(),
*               CPU_IntDisMeasStop().
*
*               This function is an INTERNAL CPU module function & MUST be implemented by application/
*               BSP function(s) [see Note #1] but SHOULD NOT be called by application function(s).
*
* Note(s)     : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer
*                   if either of the following CPU features is enabled :
*
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*
*               (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
*                       data type.
*
*                       (1) If timer has more bits, truncate timer values' higher-order bits greater
*                           than the configured 'CPU_TS_TMR' timestamp timer data type word size.
*
*                       (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
*                           timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
*                           configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
*
*                           In other words, if timer size is not a binary-multiple of 8-bit octets
*                           (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
*                           octet word size SHOULD be configured (e.g. to 16-bits).  However, the
*                           minimum supported word size for CPU timestamp timers is 8-bits.
*
*                       See also 'cpu_cfg.h   CPU TIMESTAMP CONFIGURATION  Note #2'
*                              & 'cpu_core.h  CPU TIMESTAMP DATA TYPES     Note #1'.
*
*                   (b) Timer SHOULD be an 'up'  counter whose values increase with each time count.
*
*                       (1) If timer is a 'down' counter whose values decrease with each time count,
*                           then the returned timer value MUST be ones-complemented.
*
*                   (c) (1) When applicable, the amount of time measured by CPU timestamps is
*                           calculated by either of the following equations :
*
*                           (A) Time measured  =  Number timer counts  *  Timer period
*
*                                   where
*
*                                       Number timer counts     Number of timer counts measured
*                                       Timer period            Timer's period in some units of
*                                                                   (fractional) seconds
*                                       Time measured           Amount of time measured, in same
*                                                                   units of (fractional) seconds
*                                                                   as the Timer period
*
*                                                  Number timer counts
*                           (B) Time measured  =  ---------------------
*                                                    Timer frequency
*
*                                   where
*
*                                       Number timer counts     Number of timer counts measured
*                                       Timer frequency         Timer's frequency in some units
*                                                                   of counts per second
*                                       Time measured           Amount of time measured, in seconds
*
*                       (2) Timer period SHOULD be less than the typical measured time but MUST be less
*                           than the maximum measured time; otherwise, timer resolution inadequate to
*                           measure desired times.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR  CPU_TS_TmrRd (void)
{
    CPU_TS_TMR  ts_tmr_cnts;


    ts_tmr_cnts = (CPU_TS_TMR)BSP_REG_DWT_CYCCNT;

    return (ts_tmr_cnts);
}
#endif


/*$PAGE*/
/*
*********************************************************************************************************
*                                         CPU_TSxx_to_uSec()
*
* Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds.
*
* Argument(s) : ts_cnts   CPU timestamp (in timestamp timer counts [see Note #2aA]).
*
* Return(s)   : Converted CPU timestamp (in microseconds           [see Note #2aD]).
*
* Caller(s)   : Application.
*
*               This function is an (optional) CPU module application programming interface (API)
*               function which MAY be implemented by application/BSP function(s) [see Note #1] &
*               MAY be called by application function(s).
*
* Note(s)     : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be
*                   optionally defined by the developer when either of the following CPU features is
*                   enabled :
*
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*
*               (2) (a) The amount of time measured by CPU timestamps is calculated by either of
*                       the following equations :
*
*                                                                        10^6 microseconds
*                       (1) Time measured  =   Number timer counts   *  -------------------  *  Timer period
*                                                                            1 second
*
*                                              Number timer counts       10^6 microseconds
*                       (2) Time measured  =  ---------------------  *  -------------------
*                                                Timer frequency             1 second
*
*                               where
*
*                                   (A) Number timer counts     Number of timer counts measured
*                                   (B) Timer frequency         Timer's frequency in some units
*                                                                   of counts per second
*                                   (C) Timer period            Timer's period in some units of
*                                                                   (fractional)  seconds
*                                   (D) Time measured           Amount of time measured,
*                                                                   in microseconds
*
*                   (b) Timer period SHOULD be less than the typical measured time but MUST be less
*                       than the maximum measured time; otherwise, timer resolution inadequate to
*                       measure desired times.
*
*                   (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits
*                       -- up to 32 or 64, respectively -- into microseconds.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS32_to_uSec (CPU_TS32  ts_cnts)
{
    CPU_INT64U  ts_us;
    CPU_INT64U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();
    ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

    return (ts_us);
}
#endif


#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS64_to_uSec (CPU_TS64  ts_cnts)
{
    CPU_INT64U  ts_us;
    CPU_INT64U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();
    ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

    return (ts_us);
}
#endif

static void board_device_init(void)
{
    //stm32f4_hw_uart_init();
    console_set_device(CONSOLE_DEVICE_NAME);

}

void hw_init_early(void)
{
    uart_low_config(NULL);
}
/**
 * @Synopsis  board init, caller is first task.
 */
int board_init(struct _config_init *info)
{
    bsp_tick_init();

    rcc_config();
    led_gpio_config();
    rgb_led(RGB_OFF);


    board_device_init();

    dbg2("%s: Complete.\r\n", __func__);
    return 0;
}

//CONFIG_HW_INIT(board, board_init, NULL, HW_INIT_LEVEL);
CONFIG_SW_INIT(board, board_init, NULL, SW_INIT_LEVEL_0);

